package controllers

import (
	"bytes"
	"encoding/json"
	"fmt"
	"gitchina/kly_service/errors"
	"gitchina/kly_service/models"
	"gitchina/kly_service/util"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/astaxie/beego"
	"github.com/dchest/captcha"
)

var (
	IMG_UPLOAD_PROTO_CUSTOM = 1
	IMG_UPLOAD_PROTO_RFC    = 2
)

type ImageController struct {
	beego.Controller
}

// @router /101002 [post]
func (m *ImageController) UploadImage() {
	var ext string
	var contentType string
	var imgProperties string
	var img models.Image
	var mbrID models.ID

	if val := m.Ctx.Input.GetData("mbrId"); val != nil {
		mbrID = models.ID(val.(string))
	} else {
		mbrID = ""
	}

	maxImageSize := beego.AppConfig.DefaultInt("maxImageSize", 1048576)
	cdn := beego.AppConfig.String("imageCdn")
	bn := beego.AppConfig.String("ossBucketName")
	location := beego.AppConfig.String("imageStoreLocation")

	if imgProperties = m.Ctx.Request.Header.Get("image-properties"); imgProperties == "" {
		m.Data["json"] = models.NewFailResponse(errors.New(errors.MSG_Image_Invalid_Properties))
		m.ServeJSON()
		return
	}

	var rq models.UploadImageRQ
	err := json.Unmarshal([]byte(imgProperties), &rq)
	if err != nil {
		m.Data["json"] = models.NewFailResponse(errors.New(errors.MSG_Image_Invalid_Properties))
		m.ServeJSON()
		return
	}

	var imageData []byte
	if rq.Proto == IMG_UPLOAD_PROTO_CUSTOM {
		imageData = m.Ctx.Input.RequestBody
		contentType = m.Ctx.Request.Header.Get("Content-Type")
	} else {
		f, h, err := m.GetFile("uploadimg")
		contentType = h.Header.Get("Content-Type")
		if err != nil {
			util.GetLogger().Error("[controller:UploadImage] - get file error: %s", err.Error())
			m.Data["json"] = models.NewFailResponse(errors.New(errors.MSG_Image_Not_Found))
			m.ServeJSON()
		} else {
			imageData, err = ioutil.ReadAll(f)
			if err != nil {
				util.GetLogger().Error("[controller:UploadImage] - read file error: %s", err.Error())
				m.Data["json"] = models.NewFailResponse(errors.New(errors.MSG_Image_Not_Found))
				m.ServeJSON()
			}
		}
	}

	if len(imageData) > maxImageSize {
		util.GetLogger().Error("[controller:UploadImage] - unexpected image size: %d or size > %d", len(imageData), maxImageSize)
		m.Data["json"] = models.NewFailResponse(errors.New(errors.MSG_Image_Invalid_Size))
		m.ServeJSON()
		return
	}

	if contentType == "image/jpg" {
		ext = "jpg"
	} else if contentType == "image/jpeg" {
		ext = "jpg"
	} else if contentType == "image/png" {
		ext = "png"
	} else {
		util.GetLogger().Error("[controller:UploadImage] - unexpected image ext: %s", contentType)
		m.Data["json"] = models.NewFailResponse(errors.New(errors.MSG_Image_Invalid_Ext))
		m.ServeJSON()
		return
	}

	rq.MbrID = mbrID
	rq.Data = imageData
	rq.Location = location
	rq.Ext = ext
	rq.CDN = cdn
	rq.BucketName = bn

	url, err := img.Upload(&rq)
	if err != nil {
		m.Data["json"] = models.NewFailResponse(err)
	} else {
		m.Data["json"] = models.NewOkResponse(url)
	}
	m.ServeJSON()
}

// @router /109004 [post]
func (m *ImageController) AddAdPic() {
	m.UploadImage()
}

// @router /captcha/ [get]
func (m *ImageController) GetCaptchaId() {
	domain := beego.AppConfig.String("domain")
	m.Data["json"] = models.NewOkResponse(fmt.Sprintf("%sv1/image/captcha/%s.png", domain, captcha.New()))
	m.ServeJSON()
}

// @router /captcha/:id.png [get]
func (m *ImageController) GetCaptcha() {
	var err error
	var width, height int
	var content bytes.Buffer
	if width, err = m.GetInt("width"); width < 100 || err != nil {
		width = 100
	}
	if height, err = m.GetInt("height"); height < 50 || err != nil {
		height = 50
	}
	captchaId := m.Ctx.Input.Param(":id")
	m.Ctx.ResponseWriter.Header().Set("Content-Type", "image/png")
	captcha.WriteImage(&content, captchaId, width, height)
	http.ServeContent(m.Ctx.ResponseWriter, m.Ctx.Request, captchaId+"png", time.Time{}, bytes.NewReader(content.Bytes()))
}

// @router /* [get]
func (m *ImageController) Get() {
	bn := beego.AppConfig.String("ossBucketName")
	location := beego.AppConfig.String("imageStoreLocation")
	fn := strings.Replace(m.Ctx.Input.URL(), "/v1/image/", "", 1)
	if store, err := models.NewStore(location); err == nil {
		if p, err := store.Options("fn", fn).Options("bucketname", bn).Get(); err == nil {
			m.Ctx.ResponseWriter.Header().Set("Content-Type", "image/jpg")
			m.Ctx.ResponseWriter.Header().Set("Content-Length", strconv.Itoa(len(p)))
			m.Ctx.ResponseWriter.Write(p)
		} else {
			m.Ctx.ResponseWriter.WriteHeader(404)
		}
	} else {
		m.Ctx.ResponseWriter.WriteHeader(404)
	}
}
